-- local skynet = require "skynet"
-- local gateserver = require "snax.gateserver"
-- local netpack = require "skynet.netpack" --使用netpack

-- local handler = {}
-- local CMD = {}

-- --当一个客户端链接进来，gateserver自动处理链接，并且调用该函数，必须要有
-- function handler.connect(fd, ipaddr)   
--     skynet.error("ipaddr:",ipaddr,"fd:",fd,"connect")
--     gateserver.openclient(fd) --链接成功不代表马上可以读到数据，需要打开这个套接字，允许fd接收数据
-- end

-- --当一个客户端断开链接后调用该函数，必须要有
-- function handler.disconnect(fd)   
--     skynet.error("fd:", fd, "disconnect")
-- end

-- --当fd有数据到达了，会调用这个函数，前提是fd需要调用gateserver.openclient打开
-- function handler.message(fd, msg, sz)
--     skynet.error("recv message from fd:", fd)
--     skynet.error("recv message from fd:", fd, ",  messge: " ,netpack.tostring(msg, sz)) --解包为lua可用数据
-- end

-- --如果报错就关闭该套接字
-- function handler.error(fd, msg)
--     gateserver.closeclient(fd)
-- end

-- --fd中待发送数据超过1M时调用该函数，可以不处理
-- function handler.warning(fd, size)
--     skynet.skynet("warning fd=", fd , "unsent data over 1M")
-- end

-- --一旦gateserver打开监听成功后就会调用该接口
-- --testmygateserver.lua通过给mygateserver.lua发送lua消息open触发该函数调用
-- function handler.open(source, conf) 
--     skynet.error("open by ", skynet.address(source))
--     skynet.error("listen on", conf.port)
--     skynet.error("client max", conf.maxclient)
--     skynet.error("nodelay", conf.nodelay)
-- end


-- function CMD.kick(source, fd)
--     skynet.error("source:", skynet.address(source), "kick fd:", fd)
--     gateserver.closeclient(fd)
-- end

-- function handler.command(cmd, source, ...)
--     local f = assert(CMD[cmd])
--     return f(source, ...)
-- end

-- gateserver.start(handler)


-- openmygateserver
-- [:01000010] LAUNCH snlua openmygateserver
-- [:01000010] Server start
-- [:01000012] LAUNCH snlua mygateserver
-- [:01000012] Listen on 0.0.0.0:8002
-- [:01000010] gate server setup on 8002
-- [:01000010] KILL self
-- [:01000012] ipaddr: 127.0.0.1:39016 fd: 9 connect
-- [:01000012] fd: 9 disconnect
-- 上面的结果可以看连接与断开连接都能执行，但是handler.message并没有执行。这是由于snax.gateserver
-- 基于TCP协议包装了一个两字节数据长度的协议。而现在版本的socketclient并没有按照这种协议发送。


-- agent
local skynet = require "skynet"
local gateserver = require "snax.gateserver"
local netpack = require "skynet.netpack"

local handler = {}
local CMD = {}
local agents = {}
--注册client消息专门用来将接收到的网络数据转发给agent,不需要解包，也不需要打包, 只负责转发数据
skynet.register_protocol { 
    name = "client",
    id = skynet.PTYPE_CLIENT,
}

function handler.connect(fd, ipaddr)   
    skynet.error("ipaddr:",ipaddr,"fd:",fd,"connect")
    gateserver.openclient(fd)
    local agent = skynet.newservice("myagent", fd) --连接成功就启动一个agent来代理
    agents[fd] = agent
end

function handler.disconnect(fd) --断开连接后，agent服务退出
    skynet.error("fd:", fd, "disconnect")
    local agent = agents[fd]
    if(agent) then
        --通过发送消息的方式来退出不要使用skynet.kill(agent)
        skynet.send(agent, "lua", "quit")
        agents[fd] = nil
    end
end

function handler.message(fd, msg, sz)
    local agent = agents[fd]
    skynet.redirect(agent, 0, "client", 0, msg, sz) --收到消息就转发给agent
end

function handler.error(fd, msg)
    skynet.closeclient(fd)
end

function handler.warning(fd, size)
    skynet.skynet("warning fd=", fd , "unsend data over 1M")
end

function handler.open(source, conf) 
    skynet.error("open by ", skynet.address(source))
    skynet.error("listen on", conf.port)
    skynet.error("client max", conf.maxclient)
    skynet.error("nodelay", conf.nodelay)
end

function CMD.kick(source, fd)
    skynet.error("source:", skynet.address(source), "kick fd:", fd)
    gateserver.closeclient(fd)
end

function handler.command(cmd, source, ...)
    local f = assert(CMD[cmd])
    return f(source, ...)
end

gateserver.start(handler)


-- 1、newservice watchdog启动看门狗服务，lua start conf给看门狗发送lua消息start参数为conf。
-- 2、newservice gate启动网关服务，lua open conf给网关发送lua消息open参数为 conf。
-- 3、new connection客户端连接进来。
-- 4、lua socket open fd addr给看门狗发送lua消息socket参数为open fd addr。
-- 5、newservice agent启动一个客户端代理服务，lua start {gate，fd, watchdog}给代理发送lua消息start参数为{gate，fd, watchdog}。
-- 6、lua forward fd给网关发送lua消息forward参数为fd。 （到此，连接建立成功，可以进行网络通信了）
-- 7、send requst客户端发送请求给看门狗。
-- 8、client 1 msg sz 看门狗把请求转发成client消息，session为1。
-- 9、send response 代理直接给客户端发送响应。

-- 按照从1到9的依次去查看代码，需要强调的是：
-- 1、gate主要负责的是client连接创建与断开以及接受到消息转发给agent。
-- 2、watchdog主要负责gate的创建，agent的创建与退出。
-- 3、agentt主要负责接受gate转发的请求，处理业务，然后直接把应答发送给client。


